import T from 'ant-design-vue/es/table/Table'
import get from 'lodash.get'
import { listConvertTree } from '../utils/util'
import Vue from 'vue'

export default {
  name: 'fTable',
  data() {
    return {
      delUrl: '',
      listUrl: '',
      needTotalList: [],
      parameter: [],
      filterParams: [],
      selectIndex: null,
      selectedRows: [],
      customColumns: [],
      settingColumns: [],
      selectedRowKeys: [],
      executeOnSuccess: true,
      localLoading: false,
      localDataSource: [],
      searchParams: {},
      optionAlertShow: false,
      options: {
        alert: {
          show: true, clear: () => {
            this.selectedRowKeys = []
          }
        },
        rowSelection: {
          selectedRowKeys: this.selectedRowKeys,
          onChange: this.onSelectChange
        }
      },
      localPagination: Object.assign({}, this.pagination)
    }
  },
  props: Object.assign({}, T.props, {
    rowKey: {
      type: [String, Function],
      default: 'key'
    },
    id: {
      type: [String],
      default: ''
    },
    settingKey: {
      type: String,
      default: ''
    },
    tableColumns: {
      type: Array,
      default: () => []
    },
    tableName: {
      type: [String],
      default: ''
    },
    sort: {
      type: [String],
      default: 'desc'
    },
    operatorPosition: {
      type: [String],
      default: 'top'
    },
    order: {
      type: [String],
      default: ''
    },
    api: {
      type: [String, Object],
      default: ''
    },
    showIndex: {
      type: Boolean,
      default: true
    },
    showTotal: {
      type: Boolean,
      default: false
    },
    url: {
      type: [String],
      default: ''
    },
    delAction: {
      type: [String],
      default: ''
    },

    handler: {
      type: String,
      default: ''
    },
    params: {
      type: Object,
      default: () => {
      }
    },
    operator: {
      type: Array,
      default: () => []
    },
    dataSource: {
      type: Array,
      default: () => []
    },
    pageNum: {
      type: Number,
      default: 1
    },
    pageSize: {
      type: Number,
      default: 10
    },
    treeTable: {
      type: Boolean,
      default: false
    },
    showSetting: {
      type: Boolean,
      default: false
    },
    defaultExpandAllRows: {
      type: Boolean,
      default: false
    },
    showSizeChanger: {
      type: Boolean,
      default: true
    },
    showMultipleBtn: {
      type: Boolean,
      default: true
    },
    showRadio: {
      type: Boolean,
      default: false
    },
    bordered: {
      type: Boolean,
      default: true
    },
    size: {
      type: String,
      default: 'small'
    },
    rowSelection: {
      type: Object,
      default: function() {
        return {
          selectedRowKeys: [],
          onChange: function() {

          }
        }
      }
    },
    multiple: {
      type: Boolean,
      default: true
    },
    exportBtn: {
      type: Boolean,
      default: false
    },
    autoLoad: {
      type: Boolean,
      default: true
    },

    showPagination: {
      type: String | Boolean,
      default: 'auto'
    }
  }),
  computed: {
    getBtnOperator: function() {
      return this.operator.filter(item => {
        return item.batch == undefined
      })
    },
    getMenuOperator: function() {
      return this.operator.filter(item => {
        return item.batch && item.batch == true
      })
    }
  },
  watch: {
    pageNum(val) {
      Object.assign(this.localPagination, {
        current: val
      })
    },
    pageSize(val) {
      Object.assign(this.localPagination, {
        pageSize: val
      })
    },
    showSizeChanger(val) {
      Object.assign(this.localPagination, {
        showSizeChanger: val
      })
    },
    tableColumns: {
      deep: true,
      immediate: true,
      handler: function() {
        let resultColumns = []
        let key = this.$route.name + '-tableName:' + this.tableName + ':colSettings:' + this.settingKey
        console.info('key', key)
        let columnsSetting = Vue.ls.get(key)
        if (columnsSetting == null || columnsSetting == undefined) {
          let settingColumns = []
          this.tableColumns.forEach((item) => {
            settingColumns.push(item.dataIndex)
            resultColumns.push(item)
          })
          this.settingColumns = settingColumns
        } else {
          this.settingColumns = columnsSetting
          const cols = this.tableColumns.filter(item => {
            //只显示用户选择的列和操作序号列
            if (item.title == '#' || item.dataIndex == 'action' || columnsSetting.includes(item.dataIndex)) {
              return true
            }
            return false
          })
          resultColumns = cols
        }
        if (resultColumns && resultColumns.length > 0) {
          this.customColumns = resultColumns
        } else {

          this.customColumns = this.columns
        }

      }
    }
  },
  created() {
    this.parameter = []
    this.localPagination = ['auto', true].includes(this.showPagination) && Object.assign({}, this.localPagination, {
      current: this.pageNum,
      pageSize: this.pageSize,
      pageSizeOptions: ['10', '20', '50', '100', '500'],
      showTitle: true,
      showQuickJumper: true,
      showTotal: function(total) {
        return '总记录:' + total
      },
      showSizeChanger: this.showSizeChanger
    }) || false
    console.log('this.localPagination', this.localPagination)
    this.needTotalList = this.initTotalList(this.columns)

    if (typeof this.api == 'object') {
      this.listUrl = this.api['page'] || this.api['list']
      if (this.showTotal) {
        this.listUrl = this.api['list']
      }
      this.delUrl = this.api['remove'] || this.api['delete']
    } else {
      this.listUrl = this.api
      this.delUrl = this.delAction
    }
    this.$bus.off('reloadTable')
    //监听table刷新事件
    this.$bus.on('reloadTable', (params) => {
      if (params) {
        this.searchParams = Object.assign(this.searchParams, params, { params: this.params })
        this.refresh(true)
      } else {
        this.refresh(false)
      }
    })
    this.$bus.off('resetSearchParams')
    //重置查询表单参数
    this.$bus.on('resetSearchParams', (params) => {
      if (params) {
        this.searchParams = {}
      }
      this.refresh(true, this.searchParams)
    })
    this.tableOption()
    if (this.autoLoad) {
      this.loadData()
    }
  },
  beforeDestory() {
    this.$bus.off('reloadTable')
    this.$bus.off('resetSearchParams')
    this.columns = []
  },
  mounted() {

  },
  methods: {
    onSelectChange(selectedRowKeys, selectedRows) {
      this.selectedRowKeys = selectedRowKeys
      this.selectedRows = selectedRows
    },
    getSelectedRowKey() {
      return this.selectedRowKeys
    },
    getSelectedRows() {
      return this.selectedRows
    },
    //计算某个字段以选择的求和
    getSelectedTotal(field) {
      return this.selectedRows.reduce((sum, val) => {
        const total = sum + get(val, field)
        return isNaN(total) ? 0 : total
      }, 0).toFixed(2)
    },
    tableOption() {
      if (this.optionAlertShow && this.multiple) {
        this.options = {
          alert: {
            show: true, clear: () => {
              this.selectedRowKeys = []
            }
          },
          rowSelection: {
            selectedRowKeys: this.selectedRowKeys,
            onChange: this.onSelectChange
          }
        }
        this.optionAlertShow = false
      } else {
        this.options = {
          alert: false,
          rowSelection: null
        }
        if (this.showRadio == true) {
          this.options = {
            alert: false,
            rowSelection: {
              selectedRowKeys: this.selectedRowKeys,
              type: 'radio',
              onChange: this.onSelectChange
            }
          }
        }
        if (this.showMultipleBtn == false && this.multiple) {
          this.options = {
            alert: true,
            rowSelection: {
              selectedRowKeys: this.selectedRowKeys,
              onChange: this.onSelectChange
            }
          }
        }
        this.optionAlertShow = true
      }
    },
    /**
     * 表格重新加载方法
     * 如果参数为 true, 则强制刷新到第一页
     * @param Boolean bool
     */
    refresh(bool = false, params) {
      bool && (this.localPagination = Object.assign({}, {
        current: this.localPagination.current,
        pageSize: this.pageSize
      }))
      if (params) {
        params = Object.assign(params, this.params)
        this.searchParams = Object.assign(this.searchParams, this.params, params)
      }
      console.info('showPagination', this.showPagination)
      this.loadData()
      this.clearSelected()
    },
    /**
     * 重置表格数据
     */
    reset(params) {
      this.searchParams = Object.assign({}, this.params, params)
      this.refresh(false, this.searchParams)
      this.clearSelected()
    },
    /**
     * 内置删除方法
     * @param id
     */
    remove(id, params, callback) {
      let ids = id ? id : this.selectedRowKeys.join(',')
      let data = { ids: ids }
      if (ids) {
        if (params) {
          data = Object.assign(data, params)
        }
      }
      if (ids) {
        this.http.del(this, {
          url: this.delUrl,
          data: data,
          success: function(me) {
            callback && callback()
            me.refresh()
            me.clearSelected()
          }
        })
      }
    },
    del(record, params, callback) {
      this.remove(record[this.rowKey], params, callback)
    },
    onExpand(expanded, record) {
      this.$emit('onExpand', expanded, record)
    },
    dblclick(record, event) {
      this.$emit('dblclick', record, event)
    },
    rowClassName(record, index) {
      return index === this.selectIndex ? 'checked-td-of-add-table' : ' '
    },
    customRow(record, index) {
      return {
        props: {},
        on: { // 事件
          click: (event) => {
            this.selectIndex = index
          },       // 点击行
          dblclick: (event) => {
            this.dblclick(record, event)
          },
          contextmenu: (event) => {
          },
          mouseenter: (event) => {
          },  // 鼠标移入行
          mouseleave: (event) => {
          }
        }
      }
    },
    openMultiple() {
      this.options = {
        alert: true,
        rowSelection: {
          selectedRowKeys: this.selectedRowKeys,
          onChange: this.onSelectChange
        }
      }
      this.optionAlertShow = true
    },
    closeMultiple() {
      this.options = {
        alert: false,
        rowSelection: null
      }
      this.optionAlertShow = false
      this.updateSelect([], [])
    },
    /**
     * 表格导出
     */
    tableExport(exportUrl) {
      this.$message.loading('数据导出中..', 0)
      let columns = this.getExportColumns(this.customColumns)
      let expUrl = exportUrl ? exportUrl : 'exportUrl'
      let params = Object.assign({}, this.parameter, { columns: JSON.stringify(columns) })
      this.http.exportExcel(this, {
        url: this.api[expUrl],
        data: params
      })
    },
    /**
     * 获取导出列
     */
    getExportColumns(columns) {
      let newColumns = []
      columns.forEach(column => {
        if (column.dataIndex && column.dataIndex != 'action' && column.dataIndex != '#' && column.title != '操作') {
          newColumns.push({
            name: column.title,
            isStatistics: column.isStatistics,
            key: column.dataIndex
          })
        }
      })
      return newColumns
    },
    /**
     * 加载数据方法
     * @param {Object} pagination 分页选项器
     * @param {Object} filters 过滤条件
     * @param {Object} sorter 排序条件
     */
    loadData(pagination, filters, sorter) {
      console.info('sorter', sorter)
      console.info('filters', filters)
      this.localLoading = true
      if (filters) {
        //转换为字符串
        Object.entries(filters).forEach(([key, value]) => {
          if (value) {
            this.filterParams[key] = value.join(',').toString()
          }
        })
      }
      const parameter = Object.assign({
        page: (pagination && pagination.current) || this.showPagination && this.localPagination.current || this.pageNum,
        limit: (pagination && pagination.pageSize) || this.showPagination && this.localPagination.pageSize || this.pageSize,
        handlerName: this.handler && this.handler,
        order: this.order,
        sort: this.sort
      },
        (sorter && sorter.order && { sort: sorter.order == 'ascend' ? 'asc' : 'desc' }) || {},
        (sorter && sorter.field && { order: sorter.field }) || {}, { ...this.params }, { ...this.searchParams }, { ...this.filterParams })

      console.log('查询参数:', parameter)
      this.parameter = parameter
      // 对接自己的通用数据接口需要修改下方代码中的 r.current, r.total, r.records
      let me = this
      if (this.listUrl != '') {
        this.http.get(this, {
          url: this.listUrl,
          data: parameter,
          success: function(me, data, extra) {
            if (me.treeTable) {
              let opt = {
                primaryKey: me.rowKey,
                parentKey: 'parentId',
                startPid: '0'
              }
              me.localDataSource = listConvertTree(data, opt)
              if (me.showPagination == false) {
                me.localPagination = false
              }
            } else {
              me.localPagination = me.showPagination && Object.assign({}, me.localPagination, {
                current: Number(data.current), // 返回结果中的当前分页数
                total: Number(data.total), // 返回结果中的总记录数
                showSizeChanger: me.showSizeChanger,
                pageSize: (pagination && pagination.pageSize) || me.localPagination.pageSize
              }) || false
              // 为防止删除数据后导致页面当前页面数据长度为 0 ,自动翻页到上一页
              if (data.records && data.records.length === 0 && me.showPagination && me.localPagination.current > 1) {
                me.localPagination.current--
                me.loadData()
                return
              }
              // 这里用于判断接口是否有返回 r.totalCount 且 this.showPagination = true 且 pageNo 和 pageSize 存在 且 totalCount 小于等于 pageNo * pageSize 的大小
              // 当情况满足时，表示数据不满足分页大小，关闭 table 分页功能
              try {
                if ((['auto', true].includes(me.showPagination) && data.total <= (data.current * me.localPagination.pageSize))) {
                  me.localPagination.hideOnSinglePage = true
                }
              } catch (e) {
                me.localPagination = false
              }

              let records = data.records ? data.records : data
              if (me.showTotal) {
                me.tableAddTotalRow(me.tableColumns, records)
              }
              me.localDataSource = records || data // 返回结果中的数组数据
            }
            me.localLoading = false
            //执行自定义回调
            me.$emit('onSuccess', data, extra)
          }
        })
      } else {
        me.localDataSource = me.dataSource
        me.localLoading = false
      }
    },
    initTotalList(columns) {
      const totalList = []
      columns && columns instanceof Array && columns.forEach(column => {
        if (column.needTotal) {
          totalList.push({
            ...column,
            total: 0
          })
        }
      })
      return totalList
    },
    /** 表格增加合计行 */
    tableAddTotalRow(columns, dataSource) {
      let numKey = 'rowIndex'
      let totalRow = { [numKey]: '合计' }
      columns.forEach(column => {
        let { key, dataIndex } = column
        let total = 0.0
        if (column.needTotal == true) {
          total = dataSource.reduce((sum, val) => {
            let test = get(val, dataIndex)
            if (typeof test == 'string') {
              test = 0
            }
            const total = sum + test
            return isNaN(total) ? 0 : total
          }, 0).toFixed(2)
        } else {
          total = '-'
        }
        totalRow[dataIndex] = total

      })
      dataSource.push(totalRow)
    },
    /**
     * 自定义列选择事件
     */
    onColSettingsChange(checkedValues) {
      let key = this.$route.name + '-tableName:' + this.tableName + ':colSettings:' + this.settingKey
      Vue.ls.set(key, checkedValues, 30 * 24 * 60 * 60 * 1000)
      this.settingColumns = checkedValues
      const cols = this.tableColumns.filter(item => {
        if (item.dataIndex == '#' || item.dataIndex == 'action' || this.settingColumns.includes(item.dataIndex)) {
          return true
        }
        return false
      })
      this.customColumns = cols
    },
    /**
     * 用于更新已选中的列表数据 total 统计
     */
    updateSelect(selectedRowKeys, selectedRows) {
      this.selectedRows = selectedRows
      this.selectedRowKeys = selectedRowKeys
      console.info('selectedRows', selectedRows)
      if (this.showRadio) {
        this.$emit('onSelectChange', selectedRowKeys, selectedRows)
      }
      const list = this.needTotalList
      this.needTotalList = list.map(item => {
        return {
          ...item,
          total: selectedRows.reduce((sum, val) => {
            const total = sum + parseFloat(get(val, item.dataIndex))
            return isNaN(total) ? 0 : total
          }, 0)
        }
      })
    },
    /**
     * 清空 table 已选中项
     */
    clearSelected() {
      if (this.options.rowSelection) {
        this.options.rowSelection.onChange([], [])
        this.updateSelect([], [])
      }
    },
    /**
     * 绘制操作栏
     * @returns {*}
     */
    renderOperator(slots) {
      const dropdown = (
        <a-dropdown>
          <a-menu slot='overlay'>
            {this.getMenuOperator.map((item, index) => (
              <a-menu-item v-action={item.code} key={index} onClick={() => item.handler(this, item.that)}>
                <a-icon type={item.icon}/>
                {item.name}</a-menu-item>))}
          </a-menu>

          <a-button style='margin-left: 8px'>批量操作
            <a-icon type='down'/>
          </a-button>
        </a-dropdown>
      )
      return (
        <div class='table-operator' style='padding-bottom:3px;'>
          {this.getBtnOperator.map(item => (<a-button v-action={item.code} type='primary' icon={item.icon}
                                                      onClick={() => item.handler(this, item.that)}>{item.name}</a-button>))}
          {Object.keys(slots).map(name => (<slot name={name}>{this.$slots[name]}</slot>))}
          {this.multiple && this.showMultipleBtn &&
          <a-button type='dashed' onClick={this.tableOption}>{this.optionAlertShow && '开启' || '关闭'}多选</a-button>}
          {this.selectedRowKeys.length > 0 && this.showMultipleBtn && this.operator && this.operator.length > 0 ? dropdown : ''}
          {this.exportBtn && <a-button style='margin-bottom:5px;' onClick={() => this.tableExport()}>导出</a-button>}
        </div>

      )
    },
    /**
     * 处理交给 table 使用者去处理 clear 事件时，内部选中统计同时调用
     * @param callback
     * @returns {*}
     */
    renderClear(callback) {
      if (this.selectedRowKeys.length <= 0) return null
      return (
        <a style='margin-left: 24px' onClick={() => {
          callback()
          this.clearSelected()
        }}>清空</a>
      )
    },
    renderSetting(callback) {
      // 绘制列选择列表
      const columns = this.tableColumns.map((item) => {
        return (<span>{item.title != '#' && item.title != '操作' && <a-col span={12}>
          <a-checkbox value={item.dataIndex}>{item.title}</a-checkbox>
        </a-col>}</span>)
      })
      return (
        <a-popover title='自定义列(有效期:30天)' trigger='click' placement='left'>
          <template slot='content'>
            <a-checkbox-group defaultValue={this.settingColumns} onChange={this.onColSettingsChange}>
              <a-row style='width: 400px'>
                {columns}
              </a-row>
            </a-checkbox-group>
          </template>
          <a style='float:right;'>
            <a-icon type='setting'/>
          </a>
        </a-popover>
      )
    },
    renderAlert() {
      // 绘制统计列数据
      const needTotalItems = this.needTotalList.map((item) => {
        return (<span style='margin-right: 12px'>
          {item.title}总计 <a
          style='font-weight: 600'>{!item.customRender ? item.total : item.customRender(item.total)}</a>
        </span>)
      })

      // 绘制 清空 按钮
      const clearItem = (typeof this.options.alert.clear === 'boolean' && this.options.alert.clear) ? (
        this.renderClear(this.clearSelected)
      ) : (this.options.alert !== null && typeof this.options.alert.clear === 'function') ? (
        this.renderClear(this.options.alert.clear)
      ) : null


      // 绘制 alert 组件
      return (
        <a-alert showIcon={true} type='success' style='margin-bottom: -2px;border-color:#e8e8e8;height:40px'>
          <template slot='message'>
            {this.multiple && <span style='margin-right: 12px;margin-top:3px;'>已选择: <a
              style='font-weight: 600'>{this.selectedRowKeys.length}</a></span>}
            {needTotalItems}
            {clearItem}
            {this.renderSetting()}
          </template>
        </a-alert>
      )
    }
  },
  render() {
    const props = {}
    const localKeys = Object.keys(this.$data)
    const showAlert = ((typeof this.options.alert === 'object' && this.options.alert !== null && this.options.alert.show) && typeof this.options.rowSelection.selectedRowKeys !== 'undefined' || this.options.alert) && this.multiple
    Object.keys(T.props).forEach(k => {
      const localKey = `local${k.substring(0, 1).toUpperCase()}${k.substring(1)}`
      if (localKeys.includes(localKey)) {
        props[k] = this[localKey]
        return props[k]
      }
      if (k === 'rowSelection') {
        //如果开启多选，或者单选
        if ((showAlert && this.options.rowSelection) || this.showRadio) {
          // 如果需要使用alert，则重新绑定 rowSelection 事件
          console.log('表格rowSelection配置项', this.options.rowSelection)
          props[k] = {
            ...this.options.rowSelection,
            selectedRows: this.selectedRows,
            selectedRowKeys: this.selectedRowKeys,
            onChange: (selectedRowKeys, selectedRows) => {
              console.log('选中数据', selectedRowKeys)
              this.updateSelect(selectedRowKeys, selectedRows)
              typeof this[k].onChange !== 'undefined' && this[k].onChange(selectedRowKeys, selectedRows)
            }
          }
          return props[k]
        } else if (!this.options.rowSelection) {
          // 如果没打算开启 rowSelection 则清空默认的选择项
          props[k] = null
          return props[k]
        }
      }
      this[k] && (props[k] = this[k])
      return props[k]
    })
    const table = (
      <a-table {...{ props, scopedSlots: { ...this.$scopedSlots } }} rowClassName={this.rowClassName}
               customRow={this.customRow}
               columns={this.customColumns} bordered={this.bordered} rowSelection={this.options.rowSelection}
               onChange={this.loadData} onExpand={this.onExpand}>
        {Object.keys(this.$slots).map(name => (<template slot={name}>{this.$slots[name]}</template>))}
      </a-table>
    )

    return (
      <div>
        {this.operatorPosition == 'top' && this.renderOperator(this.$slots)}
        <div class='table-wrapper'>
          {showAlert || this.showSetting ? this.renderAlert() : null}
          {table}
        </div>
        {this.operatorPosition == 'bottom' && this.renderOperator(this.$slots)}
      </div>
    )
  }
}
